//
// Saru.Math.vector4.cs: 4 Dimensional vectors and operations ;)
//
// Author:
//   Jan Van Sweevelt (vansweej@gmail.com)
//
// Copyright (C) 2007
// 

using System;

namespace Saru.Base.Math {

    public class Vector4f {
	public Vector4f() {
	    tuple = new float[4];
	}

        public Vector4f(float X, float Y, float Z, float W) {
	    tuple = new float[4];
	    tuple[0] = X;
	    tuple[1] = Y;
	    tuple[2] = Z;
	    tuple[3] = W;
	}

	public Vector4f(Vector4f V) {
	    tuple = new float[4];
	    tuple[0] = V.tuple[0];
	    tuple[1] = V.tuple[1];
	    tuple[2] = V.tuple[2];
	    tuple[3] = V.tuple[3];
	}

	// member access
	public float[] Vec4 {
	    get {
		return tuple;
	    }
 
	    set {
		tuple = value;
	    }
	}

	public float X {
	    get {
		return tuple[0];
	    }

	    set {
		tuple[0] = value;
	    }
	}

	public float Y {
	    get {
		return tuple[1];
	    }

	    set {
		tuple[1] = value;
	    }
	}

	public float Z {
	    get {
		return tuple[2];
	    }

	    set {
		tuple[2] = value;
	    }
	}

	public float W {
	    get {
		return tuple[3];
	    }

	    set {
		tuple[3] = value;
	    }
	}

        //comparison
	public static bool operator==(Vector4f V1, Vector4f V2) {
	    return V1.tuple == V2.tuple;
	}

	public static bool operator!=(Vector4f V1, Vector4f V2) {
	    return V1.tuple != V2.tuple;
	}

	public static bool operator<(Vector4f V1, Vector4f V2) {
	    return (V1.tuple[0] < V2.tuple[0] && 
		    V1.tuple[1] < V2.tuple[1] &&
		    V1.tuple[2] < V2.tuple[2] &&
		    V1.tuple[3] < V2.tuple[3]);
	}

        public static bool operator>(Vector4f V1, Vector4f V2) {
	    return (V1.tuple[0] > V2.tuple[0] && 
		    V1.tuple[1] > V2.tuple[1] &&
		    V1.tuple[2] > V2.tuple[2] &&
		    V1.tuple[3] > V2.tuple[3]);
	}

	public static bool operator<=(Vector4f V1, Vector4f V2) {
	    return (V1.tuple[0] <= V2.tuple[0] && 
		    V1.tuple[1] <= V2.tuple[1] &&
		    V1.tuple[2] <= V2.tuple[2] &&
		    V1.tuple[3] <= V2.tuple[3]);
	}

        public static bool operator>=(Vector4f V1, Vector4f V2) {
	    return (V1.tuple[0] >= V2.tuple[0] && 
		    V1.tuple[1] >= V2.tuple[1] &&
		    V1.tuple[2] >= V2.tuple[2] &&
		    V1.tuple[3] >= V2.tuple[3]);
	}

	public override bool Equals(object value) {
	    if(value == null) return false;
	    if (GetType() == value.GetType()) return this == (Vector4f)value;
	    
	    return false;
	}

	public override int GetHashCode() {
	    return tuple.GetHashCode();
	}

	// operators
	public static Vector4f operator+ (Vector4f V1, Vector4f V2) {
	    return new Vector4f(V1.tuple[0] + V2.tuple[0], 
				V1.tuple[1] + V2.tuple[1],
				V1.tuple[2] + V2.tuple[2],
				V1.tuple[3] + V2.tuple[3]); 
	}

	public static Vector4f operator- (Vector4f V1, Vector4f V2) {
	    return new Vector4f(V1.tuple[0] - V2.tuple[0], 
				V1.tuple[1] - V2.tuple[1],
				V1.tuple[2] - V2.tuple[2],
				V1.tuple[3] - V2.tuple[3]); 
	}

	public static Vector4f operator* (Vector4f V1, Single Scalar) {

	    return new Vector4f(V1.tuple[0] * Scalar, 
				V1.tuple[1] * Scalar, 
				V1.tuple[2] * Scalar,
				V1.tuple[3] * Scalar); 
	}

	public static Vector4f operator/ (Vector4f V1, Single Scalar) {
	    if(Scalar != 0.0f) {
		float reciproke = 1.0f/Scalar;

		return new Vector4f(V1.tuple[0] * reciproke, V1.tuple[1] * reciproke,
				    V1.tuple[2] * reciproke, V1.tuple[3] * reciproke);
	    }
	    else {
		return new Vector4f(float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue);
	    }
	}

	public static Vector4f operator- (Vector4f V) {
	    return new Vector4f(-V.tuple[0], 
                                -V.tuple[1],
				-V.tuple[2],
				-V.tuple[3]); 
	}

        // vector operations
	public float Length() {
            return (Single)System.Math.Sqrt(tuple[0] * tuple[0] +
                                            tuple[1] * tuple[1] +
					    tuple[2] * tuple[2] +
					    tuple[3] * tuple[3]);
	}

	public float SquaredLength() {
	    return tuple[0] * tuple[0] +
                   tuple[1] * tuple[1] +
		   tuple[2] * tuple[2] +
		   tuple[3] * tuple[3];
	}

	public float Dot(Vector4f V) {
	    return tuple[0] * V.tuple[0] +
		   tuple[1] * V.tuple[1] +
		   tuple[2] * V.tuple[2] +
		   tuple[3] * V.tuple[3];
	}

	public float Normalize() {
	    float length = Length();

            if(length > 0.0f) {
		float reciproke = 1.0f/length;		

		tuple[0] *= reciproke;
		tuple[1] *= reciproke;
		tuple[2] *= reciproke;
		tuple[3] *= reciproke;
	    }
	    else {
                length = 0.0f;
		tuple[0] = 0.0f;
		tuple[1] = 0.0f;
		tuple[2] = 0.0f;
		tuple[3] = 0.0f;
	    }

	    return length;
	}

	private float[] tuple;	
    }

    public class Vector4d {
	public Vector4d() {
	    tuple = new double[4];
	}

        public Vector4d(double X, double Y, double Z, double W) {
	    tuple = new double[4];
	    tuple[0] = X;
	    tuple[1] = Y;
	    tuple[2] = Z;
	    tuple[3] = W;
	}

	public Vector4d(Vector4d V) {
	    tuple = new double[4];
	    tuple[0] = V.tuple[0];
	    tuple[1] = V.tuple[1];
	    tuple[2] = V.tuple[2];
	    tuple[3] = V.tuple[3];
	}

	// member access
	public double[] Vec4 {
	    get {
		return tuple;
	    }
 
	    set {
		tuple = value;
	    }
	}

	public double X {
	    get {
		return tuple[0];
	    }

	    set {
		tuple[0] = value;
	    }
	}

	public double Y {
	    get {
		return tuple[1];
	    }

	    set {
		tuple[1] = value;
	    }
	}

	public double Z {
	    get {
		return tuple[2];
	    }

	    set {
		tuple[2] = value;
	    }
	}

	public double W {
	    get {
		return tuple[3];
	    }

	    set {
		tuple[3] = value;
	    }
	}

        //comparison
	public static bool operator==(Vector4d V1, Vector4d V2) {
	    return V1.tuple == V2.tuple;
	}

	public static bool operator!=(Vector4d V1, Vector4d V2) {
	    return V1.tuple != V2.tuple;
	}

	public static bool operator<(Vector4d V1, Vector4d V2) {
	    return (V1.tuple[0] < V2.tuple[0] && 
		    V1.tuple[1] < V2.tuple[1] &&
		    V1.tuple[2] < V2.tuple[2] &&
		    V1.tuple[3] < V2.tuple[3]);
	}

        public static bool operator>(Vector4d V1, Vector4d V2) {
	    return (V1.tuple[0] > V2.tuple[0] && 
		    V1.tuple[1] > V2.tuple[1] &&
		    V1.tuple[2] > V2.tuple[2] &&
		    V1.tuple[3] > V2.tuple[3]);
	}

	public static bool operator<=(Vector4d V1, Vector4d V2) {
	    return (V1.tuple[0] <= V2.tuple[0] && 
		    V1.tuple[1] <= V2.tuple[1] &&
		    V1.tuple[2] <= V2.tuple[2] &&
		    V1.tuple[3] <= V2.tuple[3]);
	}

        public static bool operator>=(Vector4d V1, Vector4d V2) {
	    return (V1.tuple[0] >= V2.tuple[0] && 
		    V1.tuple[1] >= V2.tuple[1] &&
		    V1.tuple[2] >= V2.tuple[2] &&
		    V1.tuple[3] >= V2.tuple[3]);
	}

	public override bool Equals(object value) {
	    if(value == null) return false;
	    if (GetType() == value.GetType()) return this == (Vector4d)value;
	    
	    return false;
	}

	public override int GetHashCode() {
	    return tuple.GetHashCode();
	}

	// operators
	public static Vector4d operator+ (Vector4d V1, Vector4d V2) {
	    return new Vector4d(V1.tuple[0] + V2.tuple[0], 
				V1.tuple[1] + V2.tuple[1],
				V1.tuple[2] + V2.tuple[2],
				V1.tuple[3] + V2.tuple[3]); 
	}

	public static Vector4d operator- (Vector4d V1, Vector4d V2) {
	    return new Vector4d(V1.tuple[0] - V2.tuple[0], 
				V1.tuple[1] - V2.tuple[1],
				V1.tuple[2] - V2.tuple[2],
				V1.tuple[3] - V2.tuple[3]); 
	}

	public static Vector4d operator* (Vector4d V1, Double Scalar) {

	    return new Vector4d(V1.tuple[0] * Scalar, 
				V1.tuple[1] * Scalar, 
				V1.tuple[2] * Scalar,
				V1.tuple[3] * Scalar); 
	}

	public static Vector4d operator/ (Vector4d V, Double Scalar) {
	    if(Scalar != 0.0) {
		double reciproke = 1.0/Scalar;
		
		return new Vector4d(V.tuple[0] * reciproke, V.tuple[1] * reciproke, 
				    V.tuple[2] * reciproke, V.tuple[3] * reciproke);
	    }
	    else {
		return new Vector4d(double.MaxValue, double.MaxValue, 
				    double.MaxValue, double.MaxValue);
	    } 
	}

	public static Vector4d operator- (Vector4d V) {
	    return new Vector4d(-V.tuple[0], 
                                -V.tuple[1],
				-V.tuple[2],
				-V.tuple[3]); 
	}

        // vector operations
	public double Length() {
            return (Single)System.Math.Sqrt(tuple[0] * tuple[0] +
                                            tuple[1] * tuple[1] +
					    tuple[2] * tuple[2] +
					    tuple[3] * tuple[3]);
	}

	public double SquaredLength() {
	    return tuple[0] * tuple[0] +
                   tuple[1] * tuple[1] +
		   tuple[2] * tuple[2] +
		   tuple[3] * tuple[3];
	}

	public double Dot(Vector4d V1) {
	    return tuple[0] * V1.tuple[0] +
		   tuple[1] * V1.tuple[1] +
		   tuple[2] * V1.tuple[2] +
		   tuple[3] * V1.tuple[3];
	}

	public double Normalize() {
	    double length = Length();

            if(length > 0.0f) {
		double reciproke = 1.0f/length;		

		tuple[0] *= reciproke;
		tuple[1] *= reciproke;
		tuple[2] *= reciproke;
		tuple[3] *= reciproke;
	    }
	    else {
                length = 0.0f;
		tuple[0] = 0.0f;
		tuple[1] = 0.0f;
		tuple[2] = 0.0f;
		tuple[3] = 0.0f;
	    }

	    return length;
	}

	private double[] tuple;	
    }

}
